/**
 * 实现链式调用
 * @type {string}
 */

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

function resolvePromise(promise, x, resolve, reject) { // x可能返回的是其他的promise实现
    /**
     * let p1 = new Promise((r, s) => {
     *     r()
     * }).then(() => {
     *     return p1
     * })
     * 
     * p1.then(()=> {}, (err) => {
     *     console.log(err)
     * })
     * 会走到rejected里面
     */
    if (promise === x) { // 如果返回的是promise本身， 则直接报错
        reject(new TypeError('不能返回promise本身'))
    }
    // 判断x值是不是promise，如果是Promise则用该promise的状态，如果不是则将该值作为Promise的成功态抛出
    if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
        let called = false;
        try { // 从x上取then方法，如果取不到then方法，将错误作为reason报错抛出
            let then = x.then; // 报错可能是因为then是通过defineProperty定义的then
            if (typeof then === 'function') { // 已经是最小判断了
                // x.then(y=>{}, r=>{})
                then.call(x, y => {
                    if (called) return; // 状态只能改变一次，如果调用了一次resolve或者reject就不能再调用了
                    called = true;
                    resolvePromise(promise, y,resolve, reject); // 递归解析y的值，因为resolve出来的也可能是个Promise
                }, r => { // 一旦失败就不再解析失败的结果
                    if (called) return; // 状态只能改变一次，如果调用了一次resolve或者reject就不能再调用了
                    called = true;
                    reject(r)
                })
            } else { // 没有then方法的话，说明依旧是个普通值
                resolve(x);
            }
        } catch (e) {
            if (called) return; // 状态只能改变一次，如果调用了一次resolve或者reject就不能再调用了
            called = true;
            reject(e);
        }
    } else { // 不是对象和function，是个普通值
        resolve(x)
    }
}

class Promise {
    constructor(executor) {
        this.executor = executor;
        this.state = PENDING;
        this.value = undefined; // promise默认的FULFILLED的值
        this.reason = undefined; // promise默认的REJECTED的值
        this.onResolvedCallbacks = []; // 存放成功的回调函数
        this.onRejectedCallbacks = []; // 存放失败的回调函数
        const resolve = (value) => {
            if (this.state !== PENDING) return null;
            this.state = FULFILLED;
            this.value = value;
            this.onResolvedCallbacks.forEach(cb => cb(this.value));
        }

        const reject = (reason) => {
            if (this.state !== PENDING) return null;
            this.state = REJECTED;
            this.reason = reason;
            this.onRejectedCallbacks.forEach(cb => cb(this.reason));
        }
        try {
            executor(resolve, reject);
        } catch (e) {
            reject(e);
        }
    }

    then(onFulfilled, onRejected) {
        // new Promise((re) => re(1)).then().then().then().then(res => {console.log(res)}) // 1
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
        onRejected = typeof onRejected === 'function' ? onRejected : e => {throw e};
        // 实现链式调用, 可以不停滴then下去
        let p1 = new Promise((resolve, reject) => {
            if (this.state === FULFILLED) {
                // 使用setTimeOut延迟执行的目的是，new Promise的时候，在constructor方法执行的时候就会执行回调里面的方法，这个时候还拿不到new 的Promise实例
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value); // 返回值
                        resolvePromise(p1, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            }
            if (this.state === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(p1, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                })
            }
            if (this.state === PENDING) {
                this.onResolvedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value);
                            resolvePromise(p1, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    })
                });
                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason);
                            resolvePromise(p1, x, resolve, reject);
                        } catch (e) {
                            reject(e);
                        }
                    })
                });
            }
        });
        return p1;
    }
}

/**
 * 用来测试promise是否符合规范
 */
Promise.deferred = function() {
    let dfd = {};
    dfd.promise = new Promise((resolve, reject) => {
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
}

// 拿到deferred方法返回的结果来测试是否符合规范
//npm install promises-aplus-tests -g 在命令行中使用 用于测试promise是否符合规范
//  promises-aplus-tests promise.js

module.exports = Promise;